package com.superhelper.common.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.joda.time.DateTime;

public class DateTimeUtil {
    /** yyyy-MM-dd */
    public static final String PATTERN_DEFAULT_DATE = "yyyy-MM-dd";
    /** yyyy-MM-dd HH:mm:ss */
    public static final String PATTERN_DEFAULT_DATETIME = "yyyy-MM-dd HH:mm:ss";
    /** yyyyMMdd */
    public static final String PATTERN_DATE_LONG = "yyyyMMdd";
    /** yyyyMM */
    public static final String PATTERN_YEARMONTH_LONG = "yyyyMM";
    /** yyyyMMddHHmmss */
    public static final String PATTERN_DATETIME_LONG = "yyyyMMddHHmmss";
    /** yyyy年MM月dd日 */
    public static final String PATTERN_DATE_CHINESE = "yyyy年MM月dd日";

    /**
     * Default date format = yyyy-MM-dd
     * 
     * @param date
     * @return
     */
    public static String formatDate(Date date) {
        return DateTimeUtil.format(date, PATTERN_DEFAULT_DATE);
    }

    /**
     * Default date format = yyyy-MM-dd HH:mm:ss
     * 
     * @param date
     * @return
     */
    public static String formatDatetime(Date date) {
        return DateTimeUtil.format(date, PATTERN_DEFAULT_DATETIME);
    }

    /**
     * 
     * @param date
     * @param pattern
     * @return
     */
    public static String format(Date date, String pattern) {
        try {
            return new SimpleDateFormat(pattern).format(date);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Default date format = yyyy-MM-dd
     * 
     * @param dateStr
     * @return
     */
    public static Date parseDate(String dateStr) {
        return DateTimeUtil.parse(dateStr, PATTERN_DEFAULT_DATE);
    }

    /**
     * Default date format = yyyy-MM-dd HH:mm:ss
     * 
     * @param dateStr
     * @return
     */
    public static Date parseDatetime(String dateStr) {
        return DateTimeUtil.parse(dateStr, PATTERN_DEFAULT_DATETIME);
    }

    /**
     * 
     * @param dateStr
     * @param pattern
     * @return
     */
    public static Date parse(String dateStr, String pattern) {
        try {
            return new SimpleDateFormat(pattern).parse(dateStr);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 指定增加天数
     * 
     * @param date
     * @param days
     * @return
     */
    public static Date addNDays(Date date, int days) {
        if (null == date) {
            return null;
        }
        return (new DateTime(date)).plusDays(days).toDate();
    }

    /**
     * 增加指定月数
     * 
     * @param date
     * @param months
     * @return
     */
    public static Date addNMonths(Date date, int months) {
        if (null == date) {
            return null;
        }
        if (0 == months) {
            return date;
        }
        return (new DateTime(date)).plusMonths(months).toDate();
    }

    /**
     * 增加指定小时数
     * 
     * @param date
     * @param hours
     * @return
     */
    public static Date addNHours(Date date, int hours) {
        if (null == date) {
            return null;
        }
        return (new DateTime(date)).plusHours(hours).toDate();
    }

    /**
     * 增加分钟数
     * 
     * @param date
     * @param hours
     * @return
     */
    public static Date addNMinutes(Date date, int minutes) {
        if (null == date) {
            return null;
        }
        Date da = (new DateTime(date)).plusMinutes(minutes).toDate();
        return da;
    }

    /**
     * 增加分钟数
     * 
     * @param date
     * @param seconds
     * @return
     */
    public static Date addNSeconds(Date date, int seconds) {
        if (null == date) {
            return null;
        }
        Date da = (new DateTime(date)).plusSeconds(seconds).toDate();
        return da;
    }

    /**
     * 获取指定内容
     * 
     * @param date
     * @param field
     *            Calendar.Date /Calendar.YEAR等,
     * @return 如果是Calendar.MONTH，范围为[1,12]<br/>
     *         如果是Calendar.DAY_OR_WEEK，返回值为[Calendar.SUNDAY(1),Calendar.SATURDAY
     *         (7)]
     */
    public static int getDateField(Date date, int field) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        if (Calendar.MONTH == field) {
            return c.get(field) + 1;
        }
        return c.get(field);
    }

    /**
     * 获取指定小时开始的时间,如current=2013-5-21 05:33:22 hour=6 ,则开始时间为2013-5-20 06:00:00
     * 
     * @param current
     * @param hour
     *            0<=hour<=23
     * @return
     */
    public static Date getStartTimeFromPointed(Date current, int hour) {
        if (hour > 23 || hour < 0) {
            return null;
        }
        DateTime dt = new DateTime(current);
        int curHour = dt.getHourOfDay();
        if (curHour >= 0 && curHour < hour) {
            dt = dt.minusDays(1);
        }
        dt = new DateTime(dt.getYear(), dt.getMonthOfYear(), dt.getDayOfMonth(), hour, 0, 0);
        return dt.toDate();
    }

    public static Date getFirstDayOfMonth(Date current) {
        if (null == current) {
            return null;
        }
        return getFirstDayOfMonth(current.getTime());
    }

    public static Date getFirstDayOfWeek(Date current) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); // 获取本周一的日期
        String s = formatDate(cal.getTime()) + " 00:00:00";
        Date date = parseDatetime(s);
        return date;
    }

    public static Date getFirstDayTimeOfMonth(Date current) {
        if (null == current) {
            return null;
        }
        return getFirstDayTimeOfMonth(current.getTime());

    }

    /**
     * 获取某年某月的第一个时间点
     * 
     * @param time
     * @return
     */
    public static Date getFirstDayOfMonth(Long time) {
        if (null == time) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(time);
        c.set(Calendar.DATE, 1);
        return c.getTime();
    }

    /**
     * 获取某年某月的第一个时间点
     * 
     * @param time
     * @return
     */
    public static Date getFirstDayTimeOfMonth(Long time) {
        if (null == time) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(time);
        cal.set(Calendar.DAY_OF_MONTH, 1); // 获取本月的第一天
        String s = formatDate(cal.getTime()) + " 00:00:00";
        Date date = parseDatetime(s);
        return date;

    }

    /**
     * 获取某天的0点
     * 
     * @param time
     * @return
     */
    public static Date getFirstTimeOfDate(Long time) {
        if (null == time) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(time);
        String s = formatDate(cal.getTime()) + " 00:00:00";
        Date date = parseDatetime(s);
        return date;

    }

    public static Date getFirstDayTimeOfYear(Date current) {
        if (null == current) {
            return null;
        }
        return getFirstDayTimeOfYear(current.getTime());

    }

    /**
     * 获取某年的第一个时间点
     * 
     * @param time
     * @return
     */
    public static Date getFirstDayTimeOfYear(Long time) {
        if (null == time) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(time);
        cal.set(Calendar.DAY_OF_YEAR, 1); // 获取本月的第一天
        String s = formatDate(cal.getTime()) + " 00:00:00";
        Date date = parseDatetime(s);
        return date;

    }

    public static int diffMonth(Date date1, Date date2) {
        int month = 0;
        if (date1 != null && date2 != null) {
            long beforeTime = date1.getTime();
            long endTime = date2.getTime();
            month = (int) ((endTime - beforeTime) / (1000 * 3600 * 24 * 30l));
        }
        return month;
    }

    public static int diffMonthUpper(Date date1, Date date2) {
        int month = 0;
        if (date1 != null && date2 != null) {
            long beforeTime = date1.getTime();
            long endTime = date2.getTime();
            month = (int) Math.ceil((endTime - beforeTime) / (1000 * 3600 * 24 * 30.0));
        }
        return month;
    }

    public static int getDayDiff(Date d1, Date d2) {
        if (null == d1 || null == d2) {
            return 0;
        }
        return (int) ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
    }

    public static int getHourDiff(Date d1, Date d2) {
        if (null == d1 || null == d2) {
            return 0;
        }
        return (int) ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60));
    }

    public static Date getDate(Date current) {
        if (null == current) {
            return null;
        }
        // Calendar c = Calendar.getInstance();
        // c.setTime(current);
        // c.set(Calendar.AM_PM, Calendar.AM);
        // c.set(Calendar.HOUR, 0);
        // c.set(Calendar.MINUTE, 0);
        // c.set(Calendar.SECOND, 0);
        // c.set(Calendar.MILLISECOND, 0);
        String s = formatDate(current) + " 00:00:00";
        return parseDatetime(s);
        // return c.getTime();
    }

    /**
     * 往前数前数，第几个周几
     * 如前第1个周五、前第二个周五
     * 
     * @param ago
     * @return
     */
    public static long getDayOfWeek(int ago, int dayOfWeek) {
        if (ago <= 0) {
            return 0;
        }
        Calendar c = Calendar.getInstance();
        if (c.get(Calendar.DAY_OF_WEEK) < dayOfWeek) {
            c.setTime(new Date(System.currentTimeMillis() - 7 * 86400000));
        }
        c.set(Calendar.DAY_OF_WEEK, dayOfWeek);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);

        return c.getTimeInMillis() - (ago - 1) * 7 * 86400000;
    }

    public static void main(String args[]) throws ParseException {
        Date t1 = DateTimeUtil.parse("2014-10-4", PATTERN_DEFAULT_DATE);
        System.out.println(DateTimeUtil.addNDays(t1, 30));
        System.out.println(DateTimeUtil.addNMonths(t1, 3));
        System.out.println(DateTimeUtil.addNHours(t1, 25));
        System.out.println(getStartTimeFromPointed(new DateTime(2014, 12, 3, 1, 1, 1).toDate(), 2) + " result:"
                + formatDatetime(getStartTimeFromPointed(new DateTime(2014, 12, 3, 1, 1, 1).toDate(), 2))
                        .equals("2014-12-02 02:00:00"));
        System.out.println(getStartTimeFromPointed(new DateTime(2014, 12, 3, 1, 1, 1).toDate(), 2) + " result:"
                + formatDatetime(getStartTimeFromPointed(new DateTime(2014, 12, 3, 4, 1, 1).toDate(), 2))
                        .equals("2014-12-03 02:00:00"));

        DateTime dt1 = new DateTime(2014, 12, 3, 0, 0, 0);
        DateTime dt2 = new DateTime(2013, 11, 16, 0, 0, 0);
        System.out.println(dt1.withTime(2, 0, 0, 0));
        System.out.println(dt1.minusMinutes(-60));

        System.out.println(DateTimeUtil.getStartTimeFromPointed(new Date(), 0));

        System.out.println(DateTimeUtil.getFirstDayTimeOfMonth(new Date()));
        System.out.println(DateTimeUtil.getFirstDayTimeOfYear(new Date()));
        System.out.println(DateTimeUtil.getDateField(new Date(), Calendar.MONTH));
    }

    public static boolean laterThan(Date later, Date earlier) {
        return later.compareTo(earlier) > 0;
    }

    public static boolean earlierThan(Date later, Date earlier) {
        return later.compareTo(earlier) < 0;
    }

    /**
     * 从一组时间中，找出在目标时间之后，且离目标时间最近的时间
     * 
     * @param target 需要无限逼近的时间
     * @param old 之前得到的最近时间
     * @param brand 需要判断是否更近的时间
     * @return
     */
    public static Date getClosestLaterTime(Date target, Date old, Date brand) {
        if (target == null || brand == null) {
            return old;
        }

        if (DateTimeUtil.earlierThan(target, brand)) {
            if (old == null || DateTimeUtil.laterThan(old, brand)) {
                return brand;
            }
        }
        return old;
    }

    /**
     * 从一组时间中，找出在目标时间之前，且离目标时间最近的时间
     * 
     * @param target 需要无限逼近的时间
     * @param old 之前得到的最近时间
     * @param brand 需要判断是否更近的时间
     * @return
     */
    public static Date getClosestEarlierTime(Date target, Date old, Date brand) {
        if (target == null || brand == null) {
            return old;
        }

        if (DateTimeUtil.laterThan(target, brand)) {
            if (old == null || DateTimeUtil.earlierThan(old, brand)) {
                return brand;
            }
        }
        return old;
    }

    public static boolean notBefore(Date compare, Date limit) {
        if (limit == null || compare == null) {
            return false;
        }

        return compare.equals(limit) || compare.after(limit);

    }

    /**
     * 获取下周一0点时间
     */
    public static Date getNextMinWeekDayStartDate() {
        DateTime dateTime = new DateTime(System.currentTimeMillis());
        Date date = dateTime.dayOfWeek().withMaximumValue().withTimeAtStartOfDay().plusDays(1).toDate();
        return date;
    }

    public static Date getNewDate(int year, int month, int day, int hour, int minute) {
        DateTime dateTime = new DateTime(year, month, day, hour, minute, 0);
        return dateTime.toDate();
    }
}
